
#include <v4l/v4l.h>

#include "v4li.h"
#include "v4li_events.h"

static int __v4l_signals[V4L_NUMBER_OF_SIGNALS];
void v4l_interface_class_init(gpointer g_class, gpointer class_data) {

	__v4l_signals[V4L_SIGNAL_START_DEVICE] = g_signal_new("v4li-start-event",
			G_OBJECT_CLASS_TYPE(g_class),
			G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
			G_STRUCT_OFFSET(v4lInterfaceClass, v4l_start_device),
			NULL, NULL,
			g_cclosure_marshal_VOID__VOID,
			G_TYPE_NONE, 0);

	__v4l_signals[V4L_SIGNAL_STOP_DEVICE] = g_signal_new("v4li-stop-event",
			G_OBJECT_CLASS_TYPE(g_class),
			G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
			G_STRUCT_OFFSET(v4lInterfaceClass, v4l_start_device),
			NULL, NULL,
			g_cclosure_marshal_VOID__VOID,
			G_TYPE_NONE, 0);



}
static void __init_interface_widgets(v4lInterface * v4li) {

	v4li->ls_device = gtk_list_store_new(1, G_TYPE_STRING); // Create data store ...
	v4li->cb_device = GTK_COMBO_BOX(gtk_combo_box_new_with_model(GTK_TREE_MODEL(v4li->ls_device))); //  Create combo box with store as data source.
	v4li->re_device = gtk_cell_renderer_text_new(); // Create cell renderer.
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(v4li->cb_device), v4li->re_device, TRUE); // Pack it to the combo box.
	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(v4li->cb_device), v4li->re_device,
			"text", 0,
			NULL); // Connect renderer to data source

	v4li->lb_device_name = GTK_LABEL(gtk_label_new(" - "));
	v4li->lb_device_card = GTK_LABEL(gtk_label_new(" - "));
	v4li->lb_device_driver = GTK_LABEL(gtk_label_new(" - "));
	v4li->lb_device_bus = GTK_LABEL(gtk_label_new(" - "));

	v4li->bt_start = GTK_BUTTON(gtk_button_new_with_label("start"));

	// = cb_v4l2_input
	v4li->ls_v4l2_input = gtk_list_store_new(1, G_TYPE_STRING); // Create data store ...
	v4li->cb_v4l2_input = GTK_COMBO_BOX(gtk_combo_box_new_with_model(GTK_TREE_MODEL(v4li->ls_v4l2_input))); //  Create combo box with store as data source.
	v4li->re_v4l2_input = gtk_cell_renderer_text_new(); // Create cell renderer.
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(v4li->cb_v4l2_input), v4li->re_v4l2_input, TRUE); // Pack it to the combo box.
	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(v4li->cb_v4l2_input), v4li->re_v4l2_input,
			"text", 0,
			NULL); // Connect renderer to data source

	// = cb_v4l2_standard
	v4li->ls_v4l2_standard = gtk_list_store_new(1, G_TYPE_STRING); // Create data store ...
	v4li->cb_v4l2_standard = GTK_COMBO_BOX(gtk_combo_box_new_with_model(GTK_TREE_MODEL(v4li->ls_v4l2_standard))); //  Create combo box with store as data source.
	v4li->re_v4l2_standard = gtk_cell_renderer_text_new(); // Create cell renderer.
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(v4li->cb_v4l2_standard), v4li->re_v4l2_standard, TRUE); // Pack it to the combo box.
	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(v4li->cb_v4l2_standard), v4li->re_v4l2_standard,
			"text", 0,
			NULL); // Connect renderer to data source

	// = cb_v4l2_format
	v4li->ls_v4l2_format = gtk_list_store_new(1, G_TYPE_STRING); // Create data store ...
	v4li->cb_v4l2_format = GTK_COMBO_BOX(gtk_combo_box_new_with_model(GTK_TREE_MODEL(v4li->ls_v4l2_format))); //  Create combo box with store as data source.
	v4li->re_v4l2_format = gtk_cell_renderer_text_new(); // Create cell renderer.
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(v4li->cb_v4l2_format), v4li->re_v4l2_format, TRUE); // Pack it to the combo box.
	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(v4li->cb_v4l2_format), v4li->re_v4l2_format,
			"text", 0,
			NULL); // Connect renderer to data source

	// = cb_v4l2_frmsize
	v4li->ls_v4l2_frmsize = gtk_list_store_new(1, G_TYPE_STRING); // Create data store ...
	v4li->cb_v4l2_frmsize = GTK_COMBO_BOX(gtk_combo_box_new_with_model(GTK_TREE_MODEL(v4li->ls_v4l2_frmsize))); //  Create combo box with store as data source.
	v4li->re_v4l2_frmsize = gtk_cell_renderer_text_new(); // Create cell renderer.
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(v4li->cb_v4l2_frmsize), v4li->re_v4l2_frmsize, TRUE); // Pack it to the combo box.
	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(v4li->cb_v4l2_frmsize), v4li->re_v4l2_frmsize,
			"text", 0,
			NULL); // Connect renderer to data source

	v4li->sp_width = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(0, 2400, 1));
	v4li->sp_height = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(0, 2400, 1));

	// = cb_v4l2_frmint
	v4li->ls_v4l2_frmint = gtk_list_store_new(1, G_TYPE_STRING); // Create data store ...
	v4li->cb_v4l2_frmint = GTK_COMBO_BOX(gtk_combo_box_new_with_model(GTK_TREE_MODEL(v4li->ls_v4l2_frmint))); //  Create combo box with store as data source.
	v4li->re_v4l2_frmint = gtk_cell_renderer_text_new(); // Create cell renderer.
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(v4li->cb_v4l2_frmint), v4li->re_v4l2_frmint, TRUE); // Pack it to the combo box.
	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(v4li->cb_v4l2_frmint), v4li->re_v4l2_frmint,
			"text", 0,
			NULL); // Connect renderer to data source

}
static GtkWidget * __interface_dev_conf(v4lInterface * v4li) {

	GtkFrame * frame;
	GtkVBox * vbox;
	GtkHBox * hbox;
	GtkTable * table;
	GtkLabel * label;

	frame = GTK_FRAME(gtk_frame_new("Device Information"));
	vbox = GTK_VBOX(gtk_vbox_new(FALSE, 4));
	hbox = GTK_HBOX(gtk_hbox_new(FALSE, 4));
	gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("Device:"), FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(v4li->cb_device), TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(v4li->bt_start), FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, TRUE, 0);

	table = GTK_TABLE(gtk_table_new(2, 4, FALSE));

	label = GTK_LABEL(gtk_label_new("Device: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 0, 1, 0, 1);
	label = GTK_LABEL(gtk_label_new("Card: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 0, 1, 1, 2);

	gtk_label_set_max_width_chars(v4li->lb_device_name, 20);
	gtk_misc_set_alignment(GTK_MISC(v4li->lb_device_name), 0, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->lb_device_name), 1, 2, 0, 1);

	gtk_label_set_max_width_chars(v4li->lb_device_card, 20);
	gtk_misc_set_alignment(GTK_MISC(v4li->lb_device_card), 0, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->lb_device_card), 1, 2, 1, 2);

	label = GTK_LABEL(gtk_label_new("Driver: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 2, 3, 0, 1);
	label = GTK_LABEL(gtk_label_new("Bus: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 2, 3, 1, 2);

	gtk_label_set_max_width_chars(v4li->lb_device_driver, 20);
	gtk_misc_set_alignment(GTK_MISC(v4li->lb_device_driver), 0, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->lb_device_driver), 3, 4, 0, 1);

	gtk_label_set_max_width_chars(v4li->lb_device_bus, 20);
	gtk_misc_set_alignment(GTK_MISC(v4li->lb_device_bus), 0, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->lb_device_bus), 3, 4, 1, 2);

	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), FALSE, TRUE, 0);
	gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(vbox));

	return GTK_WIDGET(frame);
}
static GtkWidget * __interface_dev_prop(v4lInterface * v4li) {

	GtkTable * table;
	GtkLabel * label;

	table = GTK_TABLE(gtk_table_new(4, 4, FALSE));

	label = GTK_LABEL(gtk_label_new("input: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach(table, GTK_WIDGET(label), 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
	gtk_table_attach(table, GTK_WIDGET(v4li->cb_v4l2_input), 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);

	label = GTK_LABEL(gtk_label_new("standard: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach(table, GTK_WIDGET(label), 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
	gtk_table_attach(table, GTK_WIDGET(v4li->cb_v4l2_standard), 3, 4, 0, 1, GTK_FILL, GTK_FILL, 0, 0);

	label = GTK_LABEL(gtk_label_new("format: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach(table, GTK_WIDGET(label), 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
	gtk_table_attach(table, GTK_WIDGET(v4li->cb_v4l2_format), 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);

	label = GTK_LABEL(gtk_label_new("frame size: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach(table, GTK_WIDGET(label), 2, 3, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
	gtk_table_attach(table, GTK_WIDGET(v4li->cb_v4l2_frmsize), 3, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 0);

	label = GTK_LABEL(gtk_label_new("frame width: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach(table, GTK_WIDGET(label), 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
	gtk_table_attach(table, GTK_WIDGET(v4li->sp_width), 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0);

	label = GTK_LABEL(gtk_label_new("frame height: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach(table, GTK_WIDGET(label), 2, 3, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
	gtk_table_attach(table, GTK_WIDGET(v4li->sp_height), 3, 4, 2, 3, GTK_FILL, GTK_FILL, 0, 0);

	return GTK_WIDGET(table);
}
static void __build_interface(v4lInterface * v4li) {

	GtkFrame * frame;

	GtkVBox * vbox;
	GtkHBox * hbox;
	GtkTable * table;
	GtkLabel * label;

	// = Frame 01
	gtk_box_pack_start(GTK_BOX(v4li), __interface_dev_conf(v4li), FALSE, FALSE, 0);


	// = Notebook
	v4li->notebook = GTK_NOTEBOOK(gtk_notebook_new());

	gtk_notebook_append_page(v4li->notebook, __interface_dev_prop(v4li), gtk_label_new("Properties"));
	
	gtk_box_pack_start(GTK_BOX(v4li), GTK_WIDGET(v4li->notebook), TRUE, TRUE, 0);

	gtk_widget_show_all(GTK_WIDGET(v4li));

}
static void ok__build_interface(v4lInterface * v4li) {

	GtkFrame * frame;
	GtkVBox * vbox;
	GtkHBox * hbox;
	GtkTable * table;
	GtkLabel * label;

	// = Frame 01
	frame = GTK_FRAME(gtk_frame_new("Device configurations"));
	vbox = GTK_VBOX(gtk_vbox_new(FALSE, 4));
	hbox = GTK_HBOX(gtk_hbox_new(FALSE, 4));
	gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("Device:"), FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(v4li->cb_device), TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(v4li->bt_start), FALSE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, TRUE, 0);

	table = GTK_TABLE(gtk_table_new(2, 4, FALSE));

	label = GTK_LABEL(gtk_label_new("Device: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 0, 1, 0, 1);
	label = GTK_LABEL(gtk_label_new("Card: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 0, 1, 1, 2);

	gtk_label_set_max_width_chars(v4li->lb_device_name, 20);
	gtk_misc_set_alignment(GTK_MISC(v4li->lb_device_name), 0, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->lb_device_name), 1, 2, 0, 1);

	gtk_label_set_max_width_chars(v4li->lb_device_card, 20);
	gtk_misc_set_alignment(GTK_MISC(v4li->lb_device_card), 0, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->lb_device_card), 1, 2, 1, 2);

	label = GTK_LABEL(gtk_label_new("Driver: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 2, 3, 0, 1);
	label = GTK_LABEL(gtk_label_new("Bus: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 2, 3, 1, 2);

	gtk_label_set_max_width_chars(v4li->lb_device_driver, 20);
	gtk_misc_set_alignment(GTK_MISC(v4li->lb_device_driver), 0, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->lb_device_driver), 3, 4, 0, 1);

	gtk_label_set_max_width_chars(v4li->lb_device_bus, 20);
	gtk_misc_set_alignment(GTK_MISC(v4li->lb_device_bus), 0, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->lb_device_bus), 3, 4, 1, 2);

	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), FALSE, TRUE, 0);
	gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(vbox));
	gtk_box_pack_start(GTK_BOX(v4li), GTK_WIDGET(frame), FALSE, FALSE, 0);

	// = Separator
	//gtk_box_pack_start(GTK_BOX(v4li), GTK_WIDGET(gtk_separator_new(GTK_ORIENTATION_HORIZONTAL)), FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(v4li), GTK_WIDGET(gtk_hseparator_new()), FALSE, FALSE, 0);

	// = Frame 02
	table = GTK_TABLE(gtk_table_new(4, 4, FALSE));


	label = GTK_LABEL(gtk_label_new("input: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 0, 1, 0, 1);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->cb_v4l2_input), 1, 2, 0, 1);

	label = GTK_LABEL(gtk_label_new("standard: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 2, 3, 0, 1);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->cb_v4l2_standard), 3, 4, 0, 1);

	label = GTK_LABEL(gtk_label_new("format: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 0, 1, 1, 2);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->cb_v4l2_format), 1, 2, 1, 2);

	label = GTK_LABEL(gtk_label_new("frame size: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 2, 3, 1, 2);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->cb_v4l2_frmsize), 3, 4, 1, 2);

	label = GTK_LABEL(gtk_label_new("frame width: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 0, 1, 2, 3);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->sp_width), 1, 2, 2, 3);

	label = GTK_LABEL(gtk_label_new("frame height: "));
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_table_attach_defaults(table, GTK_WIDGET(label), 2, 3, 2, 3);
	gtk_table_attach_defaults(table, GTK_WIDGET(v4li->sp_height), 3, 4, 2, 3);

	gtk_box_pack_start(GTK_BOX(v4li), GTK_WIDGET(table), FALSE, TRUE, 4);

	gtk_widget_show_all(GTK_WIDGET(v4li));

}
void v4l_interface_init(GTypeInstance *instance, gpointer g_class) {
	v4lInterface * v4li;

	v4li = V4L_INTERFACE(instance);

	__init_interface_widgets(v4li);
	__build_interface(v4li);
	init_interface_events(v4li);

	v4li->started = FALSE;

	v4li->v4ldrv.fd = -1;
	v4li->v4ldrv.buffer_raw = NULL;
	//v4li->v4ldrv.buffer = NULL;
	v4li->v4ldrv.dq_i = 0;
	v4li->v4ldrv.eq_i = 0;
	v4li->v4ldrv.v4lbuffers.buffers = NULL;
	v4li->v4ldrv.v4lbuffers.qtd = 0;


	// = Load device list ======================================================
	v4li->l_device = v4l_get_device_list();
	ListIterator * it;
	it = list_get_first(v4li->l_device);
	while (it) {
		GtkTreeIter iter;
		gtk_list_store_append(v4li->ls_device, &iter);
		gtk_list_store_set(v4li->ls_device, &iter, 0, it->data, -1);
		it = it->next;
	}

	// = Create aux lists ======================================================
	v4li->l_v4l2_input = list_new();
	v4li->l_v4l2_standard = list_new();
	v4li->l_v4l2_format = list_new();
	v4li->l_v4l2_frmsize = list_new();

}
GType v4l_interface_get_type(void) {
	static GType v4li_type = 0;

	if (!v4li_type) {
		const GTypeInfo v4li_info = {
			sizeof (v4lInterfaceClass),
			NULL, /* base_init */
			NULL, /* base_finalize */
			(GClassInitFunc) v4l_interface_class_init,
			NULL, /* class_finalize */
			NULL, /* class_data */
			sizeof (v4lInterface),
			0, /* n_preallocs */
			(GInstanceInitFunc) v4l_interface_init,
		};

		v4li_type = g_type_register_static(GTK_TYPE_VBOX,
				"v4lInterface",
				&v4li_info,
				0);
	}

	return v4li_type;
}
GtkWidget * v4l_interface_new(void) {
	return GTK_WIDGET(g_object_new(TYPE_V4L_INTERFACE, NULL));
}
/* ============================== */
gboolean v4l_interface_is_started(v4lInterface * v4li) {
	return v4li->started;
}
void * v4l_interface_grab_gray(v4lInterface * v4li, char * gray) {

	void * buffer;

	//if (!v4l_interface_is_started(v4li)) return NULL;

	//buffer = v4l_grab_raw( &v4li->v4ldrv );
	buffer = v4l_grab_gray(&v4li->v4ldrv, gray);
	if (!buffer) return NULL;

	return buffer;

}
void * v4l_interface_grab_rgb(v4lInterface * v4li, char * rgb) {

	void * buffer;

	//if (!v4l_interface_is_started(v4li)) return NULL;

	//buffer = v4l_grab_raw( &v4li->v4ldrv );
	buffer = v4l_grab_rgb(&v4li->v4ldrv, rgb);
	if (!buffer) return NULL;

	return buffer;

}